﻿/*!
 * Copyright (c), 上海沃恩信息科技有限公司.
 * All rights reserved.
 * Licensed under BSD (https://www.pittypat.work/bsd.html).
 */

using System.Collections.Specialized;
using System.Net.Http;
using System.Net.WebSockets;
using System.Threading.Tasks;

namespace Pittypat.Web
{
    /// <summary>
    /// 表示从一个请求中的表单字段的集合。
    /// </summary>
    sealed class RequestForm
    {
        /// <summary>
        /// 表示一个空的表单字段的集合。这是一个只读静态字段。
        /// </summary>
        private static readonly RequestForm Empty = new RequestForm(null);

        // 字段列表
        private NameValueCollection fields;

        /// <summary>
        /// 使用字段列表初始化 RequestFields 的新实例。
        /// </summary>
        /// <param name="fields">表单的字段集合。</param>
        private RequestForm(NameValueCollection fields)
        {
            this.fields = fields;
        }

        /// <summary>
        /// 获取指定名称的字段值。
        /// </summary>
        /// <param name="name">字段的名称。不区分大小写。</param>
        /// <returns>字段的值。如果没有找到字段，总是返回空字符串。</returns>
        internal string this[string name]
        {
            get
            {
                // 空字符串或 null 名称总是返回空字符串。
                if (this.fields == null || this.fields.Count == 0 || string.IsNullOrEmpty(name))
                {
                    return "";
                }

                // 首先查找查询字符串。
                foreach (var key in this.fields.AllKeys)
                {
                    if (string.Compare(key, name, true) == 0)
                    {
                        return this.fields[key] ?? "";
                    }
                }

                return "";
            }
        }

        /// <summary>
        /// 异步从请求中创建请求字段的集合。如果当前请求是 WebSocket 请求，则从 WebSocket 连接中读取，否则读取 POST 请求的表单字段。
        /// </summary>
        /// <param name="request">目标请求对象。</param>
        /// <param name="isUploadFiles">是否正在上传文件。</param>
        /// <param name="socket">目标 WebSocket。</param>
        /// <param name="recvBuffer">WebSocket 接收数据的缓冲区。</param>
        /// <param name="progress">异步操作的进度。</param>
        /// <returns>请求中的字段的集合。</returns>
        internal static async Task<RequestForm> ReadFormAsync(HttpRequestMessage request, bool isUploadFiles, WebSocket socket, byte[] recvBuffer, IAsyncProgress progress)
        {
            NameValueCollection fields = null;

            if (socket != null)
            {
                if (isUploadFiles)
                {
                    fields = new NameValueCollection(5);

                    // 上传文件时，文件信息保存在查询字符串中，将此查询字符串作为表单
                    foreach (var item in request.GetQueryNameValuePairs())
                    {
                        fields.Add(item.Key, item.Value);
                    }
                }
                else
                {
                    // 如果 WebSocket 中包含了数据，请求查询字符串中包含 __data=true|yes|1，则从 WebSocket 中读取数据
                    fields = await WebSocketHelper.ReadSocketFormAsync(request, (WebSocketAsyncProgress)progress, recvBuffer);
                }
            }
            else
            {
                // 如果是 POST 操作，从请求中读取表单字段集合
                if (request.Method.Method == "POST" && request.Content != null)
                {
                    fields = await request.Content.ReadAsFormDataAsync(progress.Token);
                }
            }
            
            // 创建新的字段集合。
            return fields == null || fields.Count == 0 ? Empty : new RequestForm(fields);
        }
    }
}
